package generation.aggregation;

import jm.audio.Instrument;
import jm.audio.io.SampleOut;
import jm.audio.synth.Add;
import jm.audio.synth.EnvPoint;
import jm.audio.synth.Envelope;
import jm.audio.synth.Oscillator;
import jm.audio.synth.StereoPan;
import jm.audio.synth.Volume;

/**
 * A basic additive synthesis instrument implementation which implements
 * envelope and volume control
 * 
 * @author Andrew Sorensen and Andrew Brown
 */
public final class HarmonicsInst extends Instrument {
	// ----------------------------------------------
	// Attributes
	// ----------------------------------------------
	/** the relative frequencies which make up this note */
	private float[] frequencies;
	/** the volumes to use for each frequency */
	private float[] volumes;
	/** Pan */
	private float pan;
	/** The sample Rate to use */
	private int sampleRate;
	/** The Oscillators to use for each frequency specified */
	private Oscillator[] wt;
	/** The envelope to apply to each Oscillator's output */
	private Envelope[] env;
	/** The volume to apply to each envelopes output */
	private Volume[] vol;
	/** Stereo Pan Audio Object */
	private StereoPan[] span;

	private boolean header = true;
	private static int count = 0;
	private SampleOut sout;
	private int numberOfOvertones = 16;
	/** the envelope data */
	private EnvPoint[] pointArray = { new EnvPoint((float) 0.0, (float) 0.0),
			new EnvPoint((float) 0.05, (float) 1.0),
			new EnvPoint((float) 0.15, (float) 0.4),
			new EnvPoint((float) 0.9, (float) 0.3),
			new EnvPoint((float) 1.0, (float) 0.0) };

	// ----------------------------------------------
	// Constructor
	// ----------------------------------------------
	/**
	 * A simple constructor
	 * 
	 * @param int sampleRate
	 */
	public HarmonicsInst(int sampleRate) {
		// Provide some defaults
		this.sampleRate = sampleRate;
		this.frequencies = new float[numberOfOvertones];
		this.volumes = new float[numberOfOvertones];
	}

	/**
	 * A constructor that allos definition of the timbral complexity
	 */
	public HarmonicsInst(int sampleRate, int numbOfOvertones) {
		// Provide some defaults
		this.sampleRate = sampleRate;
		this.numberOfOvertones = numbOfOvertones;
		this.frequencies = new float[numberOfOvertones];
		this.volumes = new float[numberOfOvertones];
	}

	// ----------------------------------------------
	// Methods
	// ----------------------------------------------
	/**
	 * Initialisation method is used to build the objects that this instrument
	 * will use
	 */
	public void createChain() {
		env = new Envelope[frequencies.length];
		vol = new Volume[frequencies.length];
		span = new StereoPan[frequencies.length];
		wt = new Oscillator[frequencies.length];
		for (int i = 0; i < numberOfOvertones; i++) {
			wt[i] = new Oscillator(this, Oscillator.SINE_WAVE, this.sampleRate,
					2);
			wt[i].setFrqRatio((float) i + 1);
			env[i] = new Envelope(wt[i], pointArray);
			vol[i] = new Volume(env[i], (float) ((1.0 / (i + 1)) * 1.5));
			span[i] = new StereoPan(vol[i], this.pan);
		}
		// And now the add object brings us back to one path.
		Add add = new Add(span);
		//SampleOut sout = new SampleOut(add);
	}
}
